package com.gitee.wsl.ext.string

/**
 * @return [this] string without the first and last characters, if possible
 */
fun String.trimDelimiters(): String = if (length >= 2) substring(1, length - 1) else this


/**
 * If this string starts and end with single quotes('') - will return the string with quotes removed
 * Otherwise, returns this string.
 *
 * @return string with the result
 */
fun String.trimSingleQuotes(): String = trimSymbols(this, "'", "'")


/**
 * If this string starts and end with quotes("") - will return the string with quotes removed
 * Otherwise, returns this string.
 *
 * @return string with the result
 */
fun String.trimQuotes(): String = trimSymbols(this, "\"", "\"")

/**
 * If this string starts and end with curly braces ({}) - will return the string without them (used in inline tables)
 * Otherwise, returns this string.
 *
 * @return string with the result
 */
fun String.trimCurlyBraces(): String = trimSymbols(this, "{", "}")

/**
 * If this string starts and end with brackets([]) - will return the string with brackets removed
 * Otherwise, returns this string.
 *
 * @return string with the result
 */
fun String.trimBrackets(): String = trimSymbols(this, "[", "]")

/**
 * If this string starts and end with a pair brackets([[]]) - will return the string with brackets removed
 * Otherwise, returns this string.
 *
 * @return string with the result
 */
fun String.trimDoubleBrackets(): String = trimSymbols(this, "[[", "]]")

/**
 * If this multiline string starts and end with triple quotes(''') - will return the string with
 * quotes and newline removed.
 * Otherwise, returns this string.
 *
 * @return string with the result
 */
fun String.trimMultilineLiteralQuotes(): String = trimMultilineQuotes("'''")
    .removePrefix(newLineChar().toString())


/**
 * If this multiline string starts and end with triple quotes(""") - will return the string with
 * quotes and newline removed.
 * Otherwise, returns this string.
 *
 * @return string with the result
 */
fun String.trimMultilineQuotes(): String = trimMultilineQuotes("\"\"\"")
    .removePrefix(newLineChar().toString())


fun String.trimMultilineQuotes(quotes: String): String {
    // if a suffix is a separator on a separate string, we need to trim whitespaces for a better user experience
    // name = '''
    // this is a "literal" multiline
    // string
    // <these whitespaces also should be removed>'''
    if (this.startsWith(quotes) && this.endsWith(quotes)) {
        val trimmedStr = this.removePrefix(quotes).removeSuffix(quotes)
        val lastNewLine = trimmedStr.lastIndexOf(newLineChar())
        if (lastNewLine != -1 &&
            // if there are only spaces after a new line - we can trim them
            // (this means that closing quotes were on a separate line):
            // """
            // aaa
            // """
            trimmedStr.removePrefix(newLineChar().toString()).substring(lastNewLine).all { it == ' ' }) {
            return trimmedStr.substring(0, lastNewLine + 1)
        }
        // we haven't found newlines (weird) or have found, but quotes are not on a separate line:
        // """
        // aaa """ <- in this case nothing to remove
        return trimmedStr
    }
    return this
}

private fun trimSymbols(
    str: String,
    prefix: String,
    suffix: String
): String {
    if (str.startsWith(prefix) && str.endsWith(suffix)) {
        return str.removePrefix(prefix).removeSuffix(suffix)
    }
    return str
}

fun String.verifyAndTrimQuotes(allowEscapedQuotesInLiteralStrings:Boolean): Any =
    when {
        // ====== multiline string (''') =======
        startsWith("'''") && endsWith("'''") -> {
            val contentString = trimMultilineLiteralQuotes()
                .checkCountOfOtherQuotes()
            val rawContent = if (allowEscapedQuotesInLiteralStrings) {
                contentString.convertSingleQuotes()
            } else {
                contentString
            }
            rawContent.convertLineEndingBackslash()
        }
        // ====== basic literal string (') =======
        startsWith("'") && endsWith("'") -> {
            val contentString = trimSingleQuotes()
            if (allowEscapedQuotesInLiteralStrings) contentString.convertSingleQuotes() else contentString
        }
        else ->
            // here we complain only about non-multiline strings, as for multiline string we have the same logic in parsing
            throw Exception(
                "Literal string should be wrapped with single quotes (''), it looks that you have forgotten" +
                        " the single quote in the end of the following string: <$this>"
            )
    }

private fun String.checkCountOfOtherQuotes(): String {
    if (this.replace("\\'", " ").getCountOfOccurrencesOfSubstring("'''") != 0) {
        throw Exception(
            "Multi-line literal basic string cannot contain 3 or more quotes (') in a row." +
                    " Please remove the quotes or set allowEscapedQuotesInLiteral " +
                    "Strings to true in the config and add escaping<$this>"
        )
    }
    return this
}